home *** CD-ROM | disk | FTP | other *** search
- ////////////////////////////////////////////////////////////////
- // EX.CPP
- // Written by Paul DiLascia for Microsoft Systems Journal 1994
- //
- // This program illustrates how to avoid losing memory when exceptions
- // are thrown. It comes in two flavors: the "GOOD" and "bad" versions.
- // To compile the bad version, type: bcc ex.cpp
- // To compile the good version, type: bcc -DGOOD ex.cpp
- // (requires Borland 4.0 C++ compiler)
- //
-
- #include <malloc.h>
- #include <stdio.h>
- #include <assert.h>
-
- //////////////////
- // Primitive memory tracking
- //
- const MAXALLOCPTRS = 50; // size of alloc tracking array
- static void* AllocPtrs[MAXALLOCPTRS]; // alloc tracking array
- static size_t AllocSizes[MAXALLOCPTRS]; // size of tracking array
- static int AllocCount = 0; // total num allocations
-
- //////////////////
- // Override global new operator to keep track of allocations.
- //
- void* operator new(size_t size)
- {
- void *p = calloc(size, 1);
- assert(p);
-
- // Store pointer in tracking array if there's room
- for (int i=0; i<MAXALLOCPTRS; i++) {
- if (AllocPtrs[i]==NULL) {
- AllocPtrs[i] = p;
- AllocSizes[i] = size;
- break;
- }
- }
- AllocCount++; // increment total count
- return p;
- }
-
- //////////////////
- // Override global delete operator to keep track of allocations.
- //
- void operator delete(void * p)
- {
- free(p);
-
- // If this is one of the allocations tracked,
- // remove it from tracking array.
- //
- for (int i=0; i<MAXALLOCPTRS; i++) {
- if (AllocPtrs[i]==p) {
- AllocPtrs[i] = NULL;
- break;
- }
- }
- AllocCount--; // decrement total allocations extant
- }
-
- ////////////////
- // Base class mother-of-all-objects.
- // Destructor must be virtual for "Deleter" class to work
- //
- class Object {
- public:
- virtual ~Object() { } // virtual destructor
- };
-
- //////////////////
- // Some other object derived from base class Object.
- // This example allocates its own array from the free store.
- //
- class CharArray : public Object {
- char* array; // allocated by constructor
- enum { arraysize=512 }; // array size in bytes
- public:
- CharArray() { array = new char [arraysize]; }
- ~CharArray() { delete [] array; }
- };
-
- //////////////////
- // Divide by zero exception class, thrown by Divide function.
- //
- class DivideByZero : public Object {
- public:
- enum ErrType { DivByZero=1, ZeroOverZero } errType;
- DivideByZero(ErrType e) : errType(e) { }
- };
-
- #ifdef GOOD
-
- //////////////////
- // "Deleter" class is used in the "good" version of the program to
- // delete objects that might otherwise be left as garbage when an
- // exception is thrown.
- //
- // This class requires a constructor for each different kind of object
- // that might be deleted. Since Object has a virtual destructor,
- // only one Deleter constrcutor is required for all Object-derived classes.
- //
- class Deleter {
- void* ptr; // object to be deleted
- enum { tvoid, tobject } iObjType; // type
- public:
- Deleter(void *pv); // "raw" memory
- Deleter(Object* pobj); // object-derived classes
- // Deleter(Other* poth); // add for other classes used...
- ~Deleter();
- };
-
- //////////////////
- // Deleter constructors are straightforward
- //
- Deleter::Deleter(void *pv) : ptr(pv), iObjType(tvoid)
- {
- }
- Deleter::Deleter(Object* pobj) : ptr(pobj), iObjType(tobject)
- {
- }
-
- //////////////////
- // Destructor destroys object "tracked" based on type.
- //
- Deleter::~Deleter()
- {
- if (iObjType==tvoid)
- delete ptr; // delete as void*
- else if (iObjType==tobject)
- delete (Object*)ptr; // delete as Object*
- else {
- assert(0);
- }
- }
- #endif
-
- //////////////////
- // Low-level divide function may throw an exception.
- //
- float Divide(float numerator, float denominator)
- {
- if (denominator==0) { // Oops!
- if (numerator==0)
- throw DivideByZero(DivideByZero::ZeroOverZero);
- else
- throw DivideByZero(DivideByZero::DivByZero);
- }
- return numerator/denominator;
- }
-
- //////////////////
- // DoDivide divides two numbers.
- // It acts as the "intermediary" function that allocates storage
- // which may be lost when an exception is thrown across the great divide
- // (pardon the pun).
- //
- float DoDivide(float numerator, float denominator)
- {
- // The following objects never get deleted in the bad version,
- // if Divide throws an exception:
- //
- char* p = new char[40]; // ordinary character array
- CharArray *po = new CharArray; // object created in free store
-
- // The following object is destroyed even in the bad version,
- // because it's created on the stack.
- //
- CharArray o;
-
- #ifdef GOOD
- // "Good" version of program uses Deleter class to
- // ensure memory objects are deleted
- //
- Deleter d1(p); // delete character array p
- Deleter d2(po); // delete object pointer po
- #endif
-
- // Do the divide:
- float result = Divide(numerator, denominator);
-
- #ifndef GOOD
- // Bad version of program uses delete to destroy allocations--But
- // these lines are never reached if Divide throws an exception!
- //
- delete [] p; // may never get deleted
- delete po; // ditto
- #endif
-
- return result;
- }
-
- //////////////////
- // Some numbers to divide
- //
- const NPAIRS=5;
- float DivPairs[NPAIRS][2] =
- {
- { 10, 2 }, { 3.14159, 2 }, { 10, 0 }, { 0, 0 }, { 2.71828, 2.71828 }
- };
-
- //////////////////
- // Main program loop:
- // Display results of dividing above pairs.
- //
- int main()
- {
- assert(AllocCount==0); // should have no allocations to start
-
- for (int i=0; i<NPAIRS; i++) {
- float numerator = DivPairs[i][0];
- float denominator = DivPairs[i][1];
- printf("%f \t/ %f \t= ", numerator, denominator);
-
- try {
- float result = DoDivide(numerator, denominator);
- printf("%f\n", result);
-
- } catch (DivideByZero dbz) {
- printf("DivideByZero(%d)\n", dbz.errType);
- }
- }
-
- // Display nasty message of any garbage is left
- //
- if (AllocCount!=0) {
- printf("\nGARBAGE LEFT! [%d objects]:\n", AllocCount);
-
- for (int i=0; i<MAXALLOCPTRS; i++) {
- if (AllocPtrs[i]!=NULL)
- printf(" Array %p [%d]\n", AllocPtrs[i], AllocSizes[i]);
- }
- }
-
- return 0;
- }
-